/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * $Revision: 10927 $
 * $Id: mainframe.cpp 10927 2016-12-04 06:14:19Z mortenmacfly $
 * $HeadURL: http://svn.code.sf.net/p/codeblocks/code/branches/release-17.xx/src/tools/cb_share_config/mainframe.cpp $
 */

#include "mainframe.h"

#include <wx/dirdlg.h>
// wxFile, wxTempFile
#include <wx/file.h>
#include <wx/filedlg.h>
// wxFileSeparator
#include <wx/filename.h>
#include <wx/msgdlg.h>
#include <wx/statusbr.h>
// wxStandardPathsBase
#include <wx/stdpaths.h>
#include <wx/settings.h>
#include <wx/tokenzr.h>

#ifndef __WXMSW__
// wxFileName
#include <wx/filename.h>
#endif

#ifdef __WXMSW__
#include <shlobj.h>
#endif

#ifdef __linux__
#include <glib.h>
#endif // __linux__

#include "tinywxuni.h"

#include <wx/settings.h>
#include <wx/intl.h>
#include <wx/string.h>

const long MainFrame::ID_LBL_STEPS = wxNewId();
const long MainFrame::ID_LBL_FILE_SRC = wxNewId();
const long MainFrame::ID_LBL_FILE_DST = wxNewId();
const long MainFrame::ID_TXT_FILE_SRC = wxNewId();
const long MainFrame::ID_BTN_FILE_SRC = wxNewId();
const long MainFrame::ID_TXT_FILE_DST = wxNewId();
const long MainFrame::ID_BTN_FILE_DST = wxNewId();
const long MainFrame::ID_CFG_SRC = wxNewId();
const long MainFrame::ID_LST_CFG = wxNewId();
const long MainFrame::ID_BTN_TRANSFER = wxNewId();
const long MainFrame::ID_BTN_UNCHECK = wxNewId();
const long MainFrame::ID_BTN_EXPORT_ALL = wxNewId();
const long MainFrame::ID_BTN_EXPORT = wxNewId();
const long MainFrame::ID_BTN_SAVE = wxNewId();
const long MainFrame::ID_BTN_CLOSE = wxNewId();

BEGIN_EVENT_TABLE(MainFrame,wxFrame)
END_EVENT_TABLE()

MainFrame::MainFrame(wxWindow* parent,wxWindowID id) :
        mFileSrc(wxT("")), mCfgSrc(0), mCfgSrcValid(false), mNodesSrc(),
        mFileDst(wxT("")), mCfgDst(0), mCfgDstValid(false), mNodesDst()
{
    wxButton* btnSave;
    wxButton* btnClose;
    wxButton* btnExport;
    wxButton* btnExportAll;
    wxButton* btnUncheck;
    wxButton* btnTransfer;

    Create(parent, id, wxT("欢迎来到Code::Blocks共享配置"), wxDefaultPosition, wxDefaultSize, wxCAPTION|wxDEFAULT_DIALOG_STYLE|wxSYSTEM_MENU|wxRESIZE_BORDER|wxCLOSE_BOX|wxMINIMIZE_BOX, _T("id"));
    SetMinSize(wxSize(640,480));
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
    bszMain = new wxBoxSizer(wxVERTICAL);
    bszSteps = new wxBoxSizer(wxHORIZONTAL);
    sbsSteps = new wxStaticBoxSizer(wxHORIZONTAL, this, wxT("要做的步骤:"));
    lblSteps = new wxStaticText(this, ID_LBL_STEPS, wxT("- 确保C::B未运行 》\n选择左侧的C::B源配置文件 》\n选择右侧的C:B目标配置文件 》\n选择要传输的节 》\n再次验证并执行传输 》\n保存修改的(右侧)配置"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_LBL_STEPS"));
    sbsSteps->Add(lblSteps, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    bszSteps->Add(sbsSteps, 1, wxALL|wxEXPAND, 5);
    bszMain->Add(bszSteps, 0, wxEXPAND, 5);
    grsFileLabel = new wxGridSizer(1, 2, 0, 0);
    lblFileSrc = new wxStaticText(this, ID_LBL_FILE_SRC, wxT("源配置文件:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_LBL_FILE_SRC"));
    grsFileLabel->Add(lblFileSrc, 0, wxALL|wxEXPAND, 0);
    lblFileDst = new wxStaticText(this, ID_LBL_FILE_DST, wxT("目标配置文件:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_LBL_FILE_DST"));
    grsFileLabel->Add(lblFileDst, 0, wxLEFT|wxEXPAND, 5);
    bszMain->Add(grsFileLabel, 0, wxLEFT|wxRIGHT|wxEXPAND, 5);
    grsFile = new wxGridSizer(1, 2, 0, 0);
    flsFileSrc = new wxFlexGridSizer(1, 2, 0, 0);
    flsFileSrc->AddGrowableCol(0);
    txtFileSrc = new wxTextCtrl(this, ID_TXT_FILE_SRC, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY, wxDefaultValidator, _T("ID_TXT_FILE_SRC"));
    flsFileSrc->Add(txtFileSrc, 0, wxEXPAND, 0);
    btnFileSrc = new wxButton(this, ID_BTN_FILE_SRC, _("..."), wxDefaultPosition, wxSize(32,-1), 0, wxDefaultValidator, _T("ID_BTN_FILE_SRC"));
    btnFileSrc->SetToolTip(wxT("选择源C::B配置文件."));
    flsFileSrc->Add(btnFileSrc, 0, wxLEFT|wxALIGN_RIGHT|wxALIGN_TOP, 5);
    grsFile->Add(flsFileSrc, 0, wxRIGHT|wxEXPAND, 5);
    flsFileDst = new wxFlexGridSizer(1, 2, 0, 0);
    flsFileDst->AddGrowableCol(0);
    txtFileDst = new wxTextCtrl(this, ID_TXT_FILE_DST, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY, wxDefaultValidator, _T("ID_TXT_FILE_DST"));
    flsFileDst->Add(txtFileDst, 0, wxEXPAND, 0);
    btnFileDst = new wxButton(this, ID_BTN_FILE_DST, _("..."), wxDefaultPosition, wxSize(32,-1), 0, wxDefaultValidator, _T("ID_BTN_FILE_DST"));
    btnFileDst->SetToolTip(wxT("选择目标C::B配置文件."));
    flsFileDst->Add(btnFileDst, 0, wxLEFT|wxALIGN_RIGHT|wxALIGN_TOP, 5);
    grsFile->Add(flsFileDst, 0, wxLEFT|wxEXPAND, 5);
    bszMain->Add(grsFile, 0, wxLEFT|wxRIGHT|wxEXPAND, 5);
    grsCfg = new wxGridSizer(1, 2, 0, 0);
    clbCfgSrc = new wxCheckListBox(this, ID_CFG_SRC, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CFG_SRC"));
    clbCfgSrc->SetMinSize(wxSize(-1,200));
    grsCfg->Add(clbCfgSrc, 0, wxRIGHT|wxEXPAND, 5);
    lstCfgDst = new wxListBox(this, ID_LST_CFG, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_LST_CFG"));
    grsCfg->Add(lstCfgDst, 0, wxLEFT|wxEXPAND, 5);
    bszMain->Add(grsCfg, 1, wxALL|wxEXPAND, 5);
    grsAction = new wxGridSizer(1, 8, 0, 0);
    btnTransfer = new wxButton(this, ID_BTN_TRANSFER, wxT("转移 >>"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_TRANSFER"));
    btnTransfer->SetToolTip(wxT("将所选内容从左向右转移."));
    grsAction->Add(btnTransfer, 0, wxALIGN_LEFT|wxALIGN_TOP, 0);
    btnUncheck = new wxButton(this, ID_BTN_UNCHECK, wxT("全部取消选中"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_UNCHECK"));
    grsAction->Add(btnUncheck, 0, wxALIGN_LEFT|wxALIGN_TOP, 0);
    btnExportAll = new wxButton(this, ID_BTN_EXPORT_ALL, wxT("全部导出"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_EXPORT_ALL"));
    grsAction->Add(btnExportAll, 0, wxALIGN_LEFT|wxALIGN_TOP, 0);
    btnExport = new wxButton(this, ID_BTN_EXPORT, wxT("导出"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_EXPORT"));
    btnExport->SetToolTip(wxT("将左侧的选择导出到C::B配置备份文件."));
    grsAction->Add(btnExport, 0, wxALIGN_LEFT|wxALIGN_TOP, 0);
    btnSave = new wxButton(this, ID_BTN_SAVE, wxT("保存"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_SAVE"));
    btnSave->SetToolTip(wxT("将右边的选择保存到C::B目标配置文件中."));
    grsAction->Add(btnSave, 0, wxLEFT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    grsAction->Add(-1,-1,1, wxEXPAND, 0);
    grsAction->Add(0,0,0, wxEXPAND, 0);
    btnClose = new wxButton(this, ID_BTN_CLOSE, wxT("关闭"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_CLOSE"));
    btnClose->SetToolTip(wxT("关闭应用程序."));
    grsAction->Add(btnClose, 0, wxALIGN_RIGHT|wxALIGN_TOP, 0);
    bszMain->Add(grsAction, 0, wxLEFT|wxRIGHT|wxEXPAND, 5);
    SetSizer(bszMain);
    bszMain->Fit(this);
    bszMain->SetSizeHints(this);
    Center();

    Connect(ID_BTN_FILE_SRC,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnFileSrcClick));
    Connect(ID_BTN_FILE_DST,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnFileDstClick));
    Connect(ID_BTN_TRANSFER,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnTransferClick));
    Connect(ID_BTN_UNCHECK,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnUncheckClick));
    Connect(ID_BTN_EXPORT_ALL,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnExportAllClick));
    Connect(ID_BTN_EXPORT,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnExportClick));
    Connect(ID_BTN_SAVE,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnSaveClick));
    Connect(ID_BTN_CLOSE,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MainFrame::OnBtnCloseClick));
}

MainFrame::~MainFrame()
{
    if (mCfgSrc) delete mCfgSrc;
    if (mCfgDst) delete mCfgDst;
}

void MainFrame::OnBtnFileSrcClick(wxCommandEvent& /*event*/)
{
    wxString filename = FileSelector();
    if (filename.IsEmpty() || SameConfig(filename, txtFileDst)) { return; }

    if (!LoadConfig(filename, &mCfgSrc) || !mCfgSrc)
    {
        mCfgSrcValid = false;
        return;
    }

    mFileSrc = filename;
    txtFileSrc->SetValue(filename);
    mCfgSrcValid = true;

    /*将配置放入wxCheckListBox*/
    OfferConfig(mCfgSrc, (wxListBox*)clbCfgSrc, &mNodesSrc);
}

void MainFrame::OnBtnFileDstClick(wxCommandEvent& /*event*/)
{
    wxString filename = FileSelector();
    if (filename.IsEmpty() || SameConfig(filename, txtFileSrc)) { return; }

    if (!LoadConfig(filename, &mCfgDst) || !mCfgDst)
    {
        /*提示：要备份(导出)配置,使用"导出"按钮,将其转换为现有的(有效Code::Blocks)配置文件,使用"转移"按钮.*/
        wxMessageBox(wxT("提示：要备份(导出)配置,使用[导出]按钮,将其转换为现有的(有效Code::Blocks)配置文件,使用[转移]按钮."),wxT("信息"), wxICON_INFORMATION | wxOK);
        mCfgDstValid = false;
        return;
    }

    mFileDst = filename;
    txtFileDst->SetValue(filename);
    mCfgDstValid = true;

    /*将配置放入wxCheckListBox*/
    OfferConfig(mCfgDst, lstCfgDst, &mNodesDst);
}

void MainFrame::OnBtnTransferClick(wxCommandEvent& /*event*/)
{
    if (mCfgSrcValid && mCfgDstValid)
    {
        if (wxMessageBox(wxT("是否确实要将选定的节点传输到目标?"),wxT("问题"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT ) == wxYES)
        {
            /*设置lstEnvVars的所有(选中)变量*/
            int items_selected = 0;
            for (unsigned int i = 0; i < clbCfgSrc->GetCount(); ++i)
            {
                if (clbCfgSrc->IsChecked(i) && (mNodesSrc.size() > i))
                {
                    items_selected++;

                    TiXmlNode* node = mNodesSrc.at(i);
                    wxString   path = clbCfgSrc->GetString(i);

                    if (!TransferNode(&node, PathToArray(path)))
                    {
                        /*无法传输节点“xxxxxxxxxx”.损坏/意外的配置结构？*/
                        wxMessageBox(wxT("无法传输节点\"") + path + wxT("\".\n损坏/意外的配置结构?"),wxT("错误"), wxICON_EXCLAMATION | wxOK);
                        return;
                    }
                }
            }

            if (items_selected)
            {
                /*传输之后更新界面(GUI)*/
                OfferConfig(mCfgDst, lstCfgDst, &mNodesDst);
                wxMessageBox(wxT("所选项目已成功传输.\n保存目标文件以永久更新配置."),wxT("信息"), wxICON_INFORMATION | wxOK);
            }
            else
            {
                wxMessageBox(wxT("没有选择要传输的项目."),wxT("警告"), wxICON_EXCLAMATION | wxOK);
            }
        }
    }
    else
    {
        wxMessageBox(wxT("无法开始传输.\n至少有一个配置为空或无效!"),wxT("错误"), wxICON_EXCLAMATION | wxOK);
    }
}

void MainFrame::OnBtnUncheckClick(wxCommandEvent& /*event*/)
{
    for (unsigned int i=0; i < clbCfgSrc->GetCount(); ++i)
        clbCfgSrc->Check(i, false);
}

void MainFrame::OnBtnExportAllClick(wxCommandEvent& /*event*/)
{
    if (!mCfgSrcValid) { return; }

    wxMessageBox(wxT("您将要将所有节点导出到C::B配置备份文件.\n"
                     "请注意,此处显示的节点不包括整个C::B配置.\n"
                     "备份文件只包含一些使用cb_share_config传输它们的节点.\n"
                     "警告:目标目录中的现有文件将被覆盖."),
                 wxT("信息"), wxICON_INFORMATION);

    wxDirDialog dlg(this, wxT("选择目标目录"), wxEmptyString,wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
    /*取消*/
    if (wxID_OK != dlg.ShowModal()) { return; }

    wxString dirname = dlg.GetPath();
    size_t   errors  = 0;

    for (unsigned int i=0; i < clbCfgSrc->GetCount(); ++i)
    {
        TiXmlDocument* doc = new TiXmlDocument();
        if (!doc)
        {
            wxMessageBox(wxT("无法创建空XML文档...?!"),wxT("错误"), wxICON_EXCLAMATION | wxOK);
            return;
        }

        TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "yes");
        TiXmlElement*     root = new TiXmlElement("CodeBlocksConfig");
        /*(Morten#1#)注:这必须与C::B的SDK(配置管理器)同步*/
        root->SetAttribute("version", 1);

        doc->LinkEndChild(decl);
        doc->LinkEndChild(root);

        if (mNodesSrc.size() <= i)
            continue;

        AttachNode(i, root);

        wxString      path     = clbCfgSrc->GetString(i);
        wxArrayString path_arr = PathToArray(path);
        wxString filename = dirname + wxFileName::GetPathSeparator() + path_arr.Item(0);
        for (size_t p=1; p<path_arr.GetCount(); p++){filename += wxT("_") + path_arr.Item(p);}
        filename += wxT(".conf");
        if (filename.IsEmpty())
            continue;

        if ( !TiXmlSaveDocument(filename, doc) )
            errors++;

        delete doc;
    }

    if (errors)
    {
        wxMessageBox(wxT("无法保存所有备份配置文件."),wxT("警告"), wxICON_EXCLAMATION | wxOK);
    }
    else
    {
        wxMessageBox(wxT("备份配置文件已保存."),wxT("信息"), wxICON_INFORMATION | wxOK);
    }
}

void MainFrame::OnBtnExportClick(wxCommandEvent& /*event*/)
{
    if (!mCfgSrcValid) { return; }

    TiXmlDocument* doc = new TiXmlDocument();
    if (!doc)
    {
        wxMessageBox(wxT("无法创建空XML文档...?!"),wxT("错误"), wxICON_EXCLAMATION | wxOK);
        return;
    }

    wxMessageBox(wxT("您将要将所选节点导出到备份C::B配置文件.\n请注意,这是不完整的,因为它只包括选定的节点.\n它的目的是备份杂项.使用cb_share_config传输它们的节点."),wxT("信息"), wxICON_INFORMATION);

    TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "yes");
    TiXmlElement*     root = new TiXmlElement("CodeBlocksConfig");

    /*(Morten#1#)注:这必须与C::B的SDK(配置管理器)同步*/
    root->SetAttribute("version", 1);

    doc->LinkEndChild(decl);
    doc->LinkEndChild(root);

    /*保存lstEnvVars的所有(选中)变量*/
    int items_selected = 0;
    for (unsigned int i=0; i < clbCfgSrc->GetCount(); ++i)
    {
        if (clbCfgSrc->IsChecked(i) && (mNodesSrc.size() > i))
        {
            items_selected++;
            AttachNode(i, root);
        }
    }// for

    if (items_selected) {
        wxString filename = wxFileSelector
                (
                        wxT("选择Code::Blocks备份配置文件"), // title 标题
                        wxT(""),                                                // default path 缺省目录
                        wxT("backup.conf"),                                     // default file 缺省文件
                        wxT("*.conf"),                                          // default extension 缺省扩展名
                        wxT("Code::Blocks配置文件类型 (*.conf)|*.conf|所有类型 (*.*)|*.*"), // wildcards 通配符
                        wxFD_SAVE                                               // flags 标志
                );

        if (!filename.IsEmpty()) {
            if (TiXmlSaveDocument(filename, doc)) { wxMessageBox(wxT("备份配置文件已保存."), wxT("信息"), wxICON_INFORMATION | wxOK); }
            else { wxMessageBox(wxT("无法保存备份配置文件."), wxT("警告"), wxICON_EXCLAMATION | wxOK); }
        }
    }else {
        wxMessageBox(wxT("没有选择要备份的项目."), wxT("警告"), wxICON_EXCLAMATION | wxOK);
    }

    delete doc;
}

void MainFrame::OnBtnSaveClick(wxCommandEvent& /*event*/) {
    if (wxMessageBox(wxT("是否确实要保存目标配置文件?"), wxT("询问"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT) == wxYES) {
        if (TiXmlSaveDocument(mFileDst, mCfgDst)) {
            wxMessageBox(wxT("目标文件已保存(更新)."), wxT("信息"), wxICON_INFORMATION | wxOK);
        } else {
            wxMessageBox(wxT("无法保存目标配置文件."), wxT("警告"), wxICON_EXCLAMATION | wxOK);
        }
    }
}

void MainFrame::OnBtnCloseClick(wxCommandEvent& /*event*/)
{
    Close();
}

wxString MainFrame::FileSelector()
{
#ifdef __WXMSW__
    TCHAR szPath[MAX_PATH];
  SHGetFolderPath(NULL, CSIDL_APPDATA, 0, 0, szPath);
  wxString config_folder = wxString(szPath) + wxT("\\codeblocks");
#else
#ifdef __linux__
    wxString config_folder = wxString::FromUTF8(g_build_filename (g_get_user_config_dir(), "codeblocks", NULL));
#else
    wxString config_folder =  wxStandardPathsBase::Get().GetUserDataDir();
#endif // __linux__

#endif

    wxString filename = wxFileSelector
            (
                    wxT("选择Code::Blocks配置文件"),
                    config_folder,
                    wxT("default.conf"),
                    wxT("*.conf"),
                    wxT("Code::Blocks配置文件 (*.conf)|*.conf|所有 (*.*)|*.*"),
                    wxFD_OPEN | wxFD_FILE_MUST_EXIST
            );

    return filename;
}

bool MainFrame::LoadConfig(const wxString& filename, TiXmlDocument** doc)
{
    if (*doc){ delete *doc;}
    *doc = new TiXmlDocument();

    if (!TiXmlLoadDocument(filename, *doc))
    {
        wxMessageBox(wxT("访问配置文件时出错!"),wxT("出错"), wxICON_EXCLAMATION | wxOK);
        return false;
    }

    if (!TiXmlSuccess(*doc)) { return false; }

    TiXmlElement* docroot = (*doc)->FirstChildElement("CodeBlocksConfig");

    if (!TiXmlSuccess(*doc)) { return false; }

    const char *vers = docroot->Attribute("version");
    if (!vers || atoi(vers) != 1)
    {
        wxMessageBox(wxT("遇到未知的配置文件版本!"),wxT("出错"), wxICON_EXCLAMATION | wxOK);
        return false;
    }

    (*doc)->ClearError();

    return true;
}

bool MainFrame::SameConfig(const wxString& filename, wxTextCtrl* txt)
{
    if (txt && filename.Matches(txt->GetValue()))
    {
        wxMessageBox(wxT("无法在同一文件之间传输配置.\n请选择两个不同的配置文件!"),wxT("错误"), wxICON_EXCLAMATION | wxOK);
        return true;
    }

    return false;
}

void MainFrame::OfferConfig(TiXmlDocument* config, wxListBox* listbox,std::vector<TiXmlNode*> *nodes)
{
    /*将配置放入wxCheckListBox或wxllistbox*/
    nodes->clear();
    listbox->Clear();
    TiXmlElement* cfgroot = config->FirstChildElement("CodeBlocksConfig");

    if (!TiXmlSuccess(config)) { return; }

    TiXmlNode* child = NULL;
    for (child = cfgroot->FirstChild(); child; child = child->NextSibling())
    {
        if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
        {
            OfferNode(&child, listbox, nodes);
        }
    }
}

void MainFrame::OfferNode(TiXmlNode** node,wxListBox* listbox,std::vector<TiXmlNode*> *nodes, const wxString& prefix)
{
    wxString section((*node)->Value(), wxConvLocal);
    const wxString &sectionLower = section.MakeLower();
    /*自动完成(缩写)*/
    if (sectionLower.Matches(wxT("auto_complete")))
    {
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("code_completion")))
    {
        /*代码完成插件令牌(标识符)替换*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            /*递归调用*/
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<code_completion>"));
        }
    }else if (sectionLower.Matches(wxT("compiler"))){
        /*编译器集合*/
        listbox->Append(wxT("<") + section + wxT(">"));
        /*完整的编译器部分*/
        nodes->push_back(*node);
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            /*递归调用*/
            if (child->Type() == TiXmlNode::TINYXML_ELEMENT) { OfferNode(&child, listbox, nodes, wxT("<compiler>")); }
        }
    }else if (sectionLower.Matches(wxT("debugger_common"))){
        /*调试器公用选项*/
        listbox->Append(wxT("<") + section + wxT(">"));
        /*完成调试器部分*/
        nodes->push_back(*node);
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            /*递归调用*/
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<debugger_common>"));
        }
    }
    else if (sectionLower.Matches(wxT("editor")))
    {
        /*编辑器颜色集合*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<editor>"));
        }
    }
    else if (sectionLower.Matches(wxT("envvars")))
    {
        /*envvar(系统环境变量)下的插件变量*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("gcv")))
    {
        /*全局变量*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("help_plugin")))
    {
        /*插件的帮助文件*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("mime_types")))
    {
        /*mime类型*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("plugins")))
    {
        /*插件*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("colours")))
    {
        /*颜色*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (sectionLower.Matches(wxT("project_manager")))
    {
        /*项目管理文件组*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {

            /*节点类型是xml元素则递归调用*/
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<project_manager>"));
        }
    }
    else if (sectionLower.Matches(wxT("tools")))
    {
        /*用户设置的工具*/
        listbox->Append(wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    } else if (prefix.Matches(wxT("<code_completion>")) && sectionLower.Matches(wxT("token_replacements"))){
        /*一级递归: code_completion -> token_replacements*/
        /*令牌替换*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (   prefix.Matches(wxT("<compiler>")) && sectionLower.Matches(wxT("sets")))
    {
        /*一级递归[编译器->设置/用户设置]: compiler -> sets/user sets*/
        /*编译器设置*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT){OfferNode(&child, listbox, nodes, wxT("<compiler><sets>"));}
        }
    }
    else if (   prefix.Matches(wxT("<compiler>")) && sectionLower.Matches(wxT("user_sets")))
    {
        /*编译器用户设置*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<compiler><user_sets>"));
        }
    }
    else if (prefix.Matches(wxT("<compiler><sets>")))
    {
        /*二级递归[编译器->设置->单独设置]: compiler -> sets -> individual sets*/
        /*单独编译器设置*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (prefix.Matches(wxT("<compiler><user_sets>")))
    {
        /*二级递归[编译器->设置->单独设置]: compiler -> sets -> individual sets*/
        /*单独编译器设置*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
    else if (   prefix.Matches(wxT("<debugger_common>")) && sectionLower.Matches(wxT("sets")))
    {
        /*一级递归:调试器通用配置(debugger_common -> sets)*/
        /*调试器设置*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<debugger_common><sets>"));
        }
    }
    else if (prefix.Matches(wxT("<debugger_common><sets>")))
    {
        /*二级递归:调试器通用-配置-单独配置(debugger_common -> sets -> individual sets)*/
        /*单独调试器配置*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }else if (   prefix.Matches(wxT("<editor>")) && sectionLower.Matches(wxT("colour_sets")))
    {
        /*一级递归:编辑器-颜色配置(editor -> colour sets)*/
        /*编辑器颜色设置*/
        TiXmlNode* child = NULL;
        for (child = (*node)->FirstChild(); child; child = child->NextSibling())
        {
            if (child->Type()==TiXmlNode::TINYXML_ELEMENT)
                OfferNode(&child, listbox, nodes, wxT("<editor><colour_sets>"));
        }
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    } else if (prefix.Matches(wxT("<editor><colour_sets>")) && !sectionLower.Matches(wxT("active_colour_set")) && !sectionLower.Matches(wxT("active_lang"))) {
        /*二级递归:编辑器-颜色配置-配色方案设置(editor -> colour sets ->theme name)*/
        // colour sets themes
        // 配色方案设置
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    } else if (prefix.Matches(wxT("<editor>")) && sectionLower.Matches(wxT("default_code"))) {
        /*一级递归:编辑器-默认代码(editor -> default code)*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    } else if (prefix.Matches(wxT("<project_manager>")) && sectionLower.Matches(wxT("file_groups"))) {
        /*一级递归:项目管理器-文件组(project_manager -> file_groups)*/
        listbox->Append(prefix + wxT("<") + section + wxT(">"));
        nodes->push_back(*node);
    }
}// OfferNode

/*传输节点*/
bool MainFrame::TransferNode(TiXmlNode** node, const wxArrayString& path)
{
    if (path.IsEmpty()) { return false; }

    TiXmlElement* element   = mCfgDst->FirstChildElement("CodeBlocksConfig");
    TiXmlNode*    node_copy = (*node)->Clone();

    if (!TiXmlSuccess(mCfgDst)) { return false; }

    for (size_t i=0; i<path.Count(); ++i)
    {
        wxString section_path = path.Item(i);

        if (element->NoChildren())
        {

            /*元素没有子元素->创建以节命名的新子元素*/
            element = (TiXmlElement*) element->InsertEndChild(TiXmlElement(
#if wxUSE_UNICODE
                            section_path.mb_str(wxConvUTF8)
#else
                            (wxChar*)section_path.mb_str()
#endif
                    ));
        }else{
            /*元素有子元素->查找以节命名的子元素*/
            TiXmlElement* new_element = element->FirstChildElement(
#if wxUSE_UNICODE
                    section_path.mb_str(wxConvUTF8)
#else
                    (wxChar*)section_path.mb_str()
#endif
            );

            if (!new_element)
            {
                /*找不到子项->创建以节命名的子项*/
                element = (TiXmlElement*) element->InsertEndChild(TiXmlElement(
#if wxUSE_UNICODE
                        section_path.mb_str(wxConvUTF8)
#else
                        (wxChar*)section_path.mb_str()
#endif
                ));
            } else {

                /*子项已找到->切换到此子项*/
                element = new_element;
            }
        }

        if (!element) { return false; }

        /* ...继续下一节.*/
    }

    TiXmlNode* parent_node = element->Parent();
    parent_node->ReplaceChild(element, *node_copy);

    return true;
}// TransferNode

/*附加节点*/
void MainFrame::AttachNode(size_t idx, TiXmlElement* root)
{
    TiXmlNode*    node     = mNodesSrc.at(idx);
    wxString      path     = clbCfgSrc->GetString(idx);
    wxArrayString path_arr = PathToArray(path);

    TiXmlElement* element  = root;
    for (size_t p=0; p<path_arr.Count(); ++p)
    {
        wxString section_path = path_arr.Item(p);
        if (element->NoChildren())
        {
            /*元素没有子元素->创建以节命名的新子元素*/
            element = (TiXmlElement*) element->InsertEndChild(TiXmlElement(
#if wxUSE_UNICODE
                            section_path.mb_str(wxConvUTF8)
#else
                            (wxChar*)section_path.mb_str()
#endif
                    ));
        } else {
            /*元素有子元素->查找以节(section)命名的子元素*/
            TiXmlElement* new_element = element->FirstChildElement(
#if wxUSE_UNICODE
                    section_path.mb_str(wxConvUTF8)
#else
                    (wxChar*)section_path.mb_str()
#endif
            );

            if (!new_element)
            {
                /*找不到子级->创建以节(section)命名的子级*/
                element = (TiXmlElement*) element->InsertEndChild(TiXmlElement(
#if wxUSE_UNICODE
                        section_path.mb_str(wxConvUTF8)
#else
                        (wxChar*)section_path.mb_str()
#endif
                ));
            } else {
                /*找到子对象->切换到此子对象*/
                element = new_element;
            }
        }

        if (!element) { return; }
        /* ...继续下一节.*/
    }// for

    TiXmlNode* parent_node = element->Parent();
    parent_node->ReplaceChild(element, *node);
}// AttachNode

/*路径转数组*/
wxArrayString MainFrame::PathToArray(const wxString& path)
{
    wxString      path_modifications = path;
    wxArrayString as;

    if (path_modifications.Freq('<')==path_modifications.Freq('>'))
    {
        wxStringTokenizer tkz(path_modifications, wxT("<"));
        while (tkz.HasMoreTokens())
        {
            wxString token = tkz.GetNextToken();
            if (!token.IsEmpty()){as.Add(token.RemoveLast());}
        }
    } else {
        wxMessageBox(wxT("无法将XML路径转换为字符串数组!"),wxT("断言失败."), wxICON_EXCLAMATION | wxOK);
    }

    return as;
}// PathToArray

/*载入Xml文档*/
bool MainFrame::TiXmlLoadDocument(const wxString& filename, TiXmlDocument* doc)
{
    if (!doc || !wxFile::Access(filename, wxFile::read)){return false;}

    wxFile file(filename);
    size_t len = file.Length();

    char *input = new char[len+1];
    input[len] = '\0';
    file.Read(input, len);

    doc->Parse(input);
    delete[] input;
    return true;
}// TiXmlLoadDocument

/*保存Xml文档*/
bool MainFrame::TiXmlSaveDocument(const wxString& filename, TiXmlDocument* doc)
{
    if (!doc) { return false; }

    TiXmlPrinter printer;
    printer.SetIndent("\t");
    doc->Accept(&printer);

    wxTempFile file(filename);
    if (file.IsOpened())
    {
        if (file.Write(printer.CStr(), printer.Size()) && file.Commit()){return true;}
    }

    return false;
}// TiXmlSaveDocument

/*操作XML文件成功*/
bool MainFrame::TiXmlSuccess(TiXmlDocument* doc)
{
    if (doc->ErrorId())
    {
        wxMessageBox(wxT("TinyXML错误: ") +
                     #if wxUSE_UNICODE
                     wxString(doc->ErrorDesc(), wxConvUTF8),
#else
                wxString(doc->ErrorDesc()),
#endif
                     wxT("错误"), wxICON_EXCLAMATION | wxOK);
        return false;
    }

    return true;
}// TiXmlSuccess
